Homework 2 Image Signal Processing

Zhen Tong 120090694

header

In this project, we build a Image Signal Processing Pipeline with Python. In this ISP pipeline project, our contribution includes:

Dead Pixel Correction

Since the Sensor is a physical device, it is difficult to avoid bad points.

Idea

The DPC is in two steps: detect the dead pixel, and recover it. Detection is compute the difference of each pixel and if the all the neighbor difference is bigger than the threshold, it is a dead pixel:

diffx(Pi,j)=|Pi,jPx|Pi,j={Deadxneighbordiffx(Pi,j)Not DeadOtherwise

Assign the value of the dead pixel with neighbor mean

Compute the second order gradient of the image at the dead pixel in four direction. Assign the dead pixel as the average of the most "smooth "direction, which is the minimal one of the four absolute value.

dv=|2p0p2p7|dh=|2p0p4p5|ddl=|2p0p1p8|ddr=|2p0p3p6|

Acceleration

Because the DPC process need to iterate all the pixel to find the dead pixel, which is O(N2) time complexity. To speedup, we need to avoid the nested for loop inpython, instead use the vectorize compute with numpy. First we generate 9 copy of the image matrix, and generate all the position to be compute, and record them in y_ids, and x_ids. We compute the mask matrix for all the dead pixel.

Ouptut

The following figures are "dead pixel when "threshold = 100, 150, 200. As you can see, they are not dead pixel most of the time, instead, they are the edges of the image. Because the DPC detection use gradient, and smooth the image unintentionally, we shouldn't set it too low.

Black Level Compensation

Due to the existence of Sensor leakage current, the lens has just been put into a completely black environment, and the original output data of the Sensor is not 0; And we want the original number to be 0 when it's all black.

R=R+BoffsetGr=Gr+Groffset+αRGb=Gb+Gboffset+βBB=B+Boffset

Anti Aliasing Filter

Do the convolution of the image with the kernel to avoid aliasing.

[1010100000108010000010101]

The acceleration of convolution is the same in Edge Enhancement, see later.

Auto White Balance and Gain Control

By adjust the scale of RGrGbB, the quality of the image can improve.

R=R×rgainB=B×bgainGr=Gr×grgainGb=Gb×gbgain

However, this process need hyperparameter, which depends on color expertise.

Color Filter Array Interpolation

Idea

We need to interpolate the [height, width, 3] RGB image from the raw [height, width] Matrix. The matrix is in rggb bayer pattern, which is:

rggb

What we need to is to interpolate from the 2 dimension array to 3 dimension with Malvar (2004) demosaicing algorithm.

There are several situation of interpolation:

Color in Bayer/Target ColorRGB
Rrgrbr
Grrgrggrbgr
Gbrgbggbbgb
Brbgbb

Following the weight of the algorithm in the figure,

cfa_rule

For example G at R location is:

gr=4Xy,xXy2,xXy,x2Xy+2,xXy,x+2+2(Xy+1,x+Xy,x+1+Xy1,x+Xy,x1)8

Acceleration

In the interpolation, intuitively we need to use the nested for loop, which is in N2 time. To speedup the code in python, we can use the Indices Generationi: Meshgrid is used to generate indices for accessing elements of the 2D image in a structured manner. This generates arrays y_indices and x_indices representing the y and x coordinates of pixels in the padded image.

The meshgrid will generate the 2d coordinate of step-size = 2. Then, we can extract the rs, grs, gbs, and bs matrix from the bayer matrix by:

Then, we can interpolate in matrix level for 4 times:

After all, remember to clip the image.

Normalization

Notably, without normalization, the matplotlib.pyplot can not transfrom the scale of CFA output to the 0-255, or 0-1 scale (all white in the RGB Image bellow), we need to manually normalize it into 0-255 or 0-1.

After normalization:

X=Xmin(X)max(X)min(X)

 

RGB2YUV

Idea

We need to change to YUV for the further process but not direct using RGB, because YUV can separate the Chroma(color informationCr , Cb) and Luma(intensity information Y). Notice that the matrix transform of range [0, 1] and [0, 255] is different, here our RGB range is [0, 255]

 

Acceleration

Change the pixel by pixel transform into matrix transform

Output

In the following content, when we show the YUV output, we are actually showing the YUV[:, :, 0], the first channel Luma, but not the 3-Channel image. Next, we try to improve the edge, contrast, and brightness quality of the image one the first channel of YUV.

We can draw the histogram of the YUV channels, to monitor the shape change of the distribution later.

Edge Enhancement

Idea

The edge enhancement includes two parts: compute the convolution of edge filter, and compute the edge map loop up table (EMLUT). With gains: g1,g2=32,128, threstholds: x1,x2=32,64, the transform function is in shape of:

f(x)={128xif x<640if 64<x<3232xif 32<x<320if 32<x<64128xif x>64

Speed up

First, in the convolution part, the filter kernel is a 3x5 matrix. We can again use the meshgrid to divide the 15 channels of image from the first channel of YUV image. Each channel of the 15 channel corespond to one weight of the kernel filter. Then compute the weighted sum

Then the piecewise function transform to the convolution output can be speed up with mask operation in numpy. The mask records all the pixels that in the range of the given condition. Then it can be used to assign the value by indices accessing.

Output

After computing the EMLUT(x), clip the EMLUT(x) and add it to the image as an output:

Brightness/Contrast Control

Idea

Brightness control is :

Y×contrast+brightessi.e. αY+β

This operation is first move the distribution to the right of brightness scale, and then enlarge the variance with contrast scale. In the example image, I choose brightness as 12.3208, and contrast = 0.9249.

Here we minus the median value to control the moving shape of the distribution. One tips here for the adjustment of the parameter is that you can first pin some point of the distribution, and the calculate the parameter using the least square method.

In the histogram above, we can observe that there is a high frequent around 30-40, and we don't want the high value part moving too far from 150. Therefore we can set a group of function from the original distribution to the target distribution:

40α+β=5075α+β=80125α+β=130150α+β=150

By the LSM, we can get the β=12.3208 , and α=0.9249.

Notice that now the clip range is no longer [16, 235], the Y channel is in range of [16, 235].

Output

In the output image, the sky is brighter, and the shade of tree is darker (left of the image). In the histogram, the darker part is moved from around 30 to around 45.

False Color Suppression

Idea

False Color was caused from the CFA interpolation. In short, false color is introduced into the image when the predicted color is inaccurate, especially in the gray area.

First compute the gain of u dimension and v dimension by this piecewise function:

Cb,Cr={Cb,Cr|EM(y,x)|fcsEdge1gain×(|EM|128)65536+128fcsEdge1<|EM(y,x)|<fcsEdge20|EM(y,x)|fcsEdge2

In this figure the edge map distribution is:

EM_stat

Therefore, I set the fcsEdge1=16, and fcsEdge2=32

Acceleration

Again use the mask boolean indices to assign the value in a vectorization way:

Output

In the output, we can see the Cb part improved, and the darker part in Cb become brighter. In the RGB level, the darker part become less red, and more blue.

Hue/Saturation control

Idea

HSC is in two step: the Hue control, and the Saturation control. In the Hue tuning, the two channels range are first moved from [0-256] to [-128, 128], then using the sine of Hue parameter to get the new Cr, and Cb channel value.

YCr=(YCr128)×cos(h)+(YCb128)×sin(h)+128YCb=(YCb128)×cos(h)+(YCr128)×sin(h)+128

Then in the Saturation control step, with a linear transform, we can output the tuned image of UV channels:

Y=s(Y128)256+128

Output

In the image below, we can observe both Cr and Cb showed more details, and more contrast.

Normalize and output the RBG

After all, assign the Y channel as the BCC output, and assign the Cr, Cb channel as the HSC output.

How to Run

You can run the code without checking detail

Or you can check image change of each stage in the pipeline with

Results

You are free to access the result of each step under the ./data directory.

Compared to the rawpy Output without Gamma Correction

Our ISP Output

References

Github